package com.pe.pgn.clubpgn.dao.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;

import javax.sql.DataSource;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.pe.pgn.clubpgn.common.CLPConstantes;
import com.pe.pgn.clubpgn.dao.AsignacionArticuloDao;
import com.pe.pgn.clubpgn.dao.hibernate.GenericDaoHibernate;
import com.pe.pgn.clubpgn.domain.ClpbAlmacen;
import com.pe.pgn.clubpgn.domain.ClpbDocumentoMovArticulo;
import com.pe.pgn.clubpgn.domain.ClpdArticulo;
import com.pe.pgn.clubpgn.domain.ClpdDocumentoMovArticulo;
import com.pe.pgn.clubpgn.domain.ClpmCatalogo;
import com.pe.pgn.clubpgn.domain.ClpmStockAlmacenCatalogo;
import com.pe.pgn.clubpgn.domain.ClpmTransaccionArticulo;
import com.pe.pgn.clubpgn.domain.ClprPremioCatalogo;
import com.pe.pgn.clubpgn.domain.beans.BNAsignacionArticuloCatalogoDetalle;
import com.pe.pgn.clubpgn.webapp.util.ValidationUtil;

@Repository("asignacionArticuloDao")
public class AsignacionArticuloDaoImpl extends
GenericDaoHibernate<ClpbDocumentoMovArticulo, Long> implements
AsignacionArticuloDao {
	
	public AsignacionArticuloDaoImpl() {
		super(ClpbDocumentoMovArticulo.class);
	}

	private JdbcTemplate jdbcTemplate;

	@Autowired
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}

	@SuppressWarnings("rawtypes")
	public List<ClpbDocumentoMovArticulo> busquedaDocumentoAsignacionPorFiltros(
			String deDocumento, Long coAlmacenOrigen, Long coAlmacenDestino) {
		StringBuffer query = new StringBuffer();

		query.append("select a.id as id ");
		query.append("	from clpb_documento_mov_articulo a ");
		query.append("	where 1 = 1 ");

		if (StringUtils.isNotBlank(deDocumento)) {
			query.append("		and upper(trim(a.de_documento)) like '%").append(
					deDocumento.trim().toUpperCase()).append("%'");
		}
		if (coAlmacenOrigen.intValue() > 0) {
			query.append("		and a.co_almacen_origen = ")
					.append(coAlmacenOrigen);
		}

		if (coAlmacenDestino.intValue() > 0) {
			query.append("		and a.co_almacen_destino = ").append(
					coAlmacenDestino);
		}
		
		query.append("		and a.st_documento_mov_articulo = '").append(
				CLPConstantes.ST_VERDADERO).append("'");
		
		query.append("		and a.st_indicador_tipo_documento = '").append(
				CLPConstantes.ST_DOCUMENTO_ASIGNACION_ARTICULO_A_CATALOGO).append("'");
		
		System.out.print(query.toString());
		List lista = jdbcTemplate.queryForList(query.toString());
		List<ClpbDocumentoMovArticulo> listaDocumentos = new ArrayList<ClpbDocumentoMovArticulo>();
		for (Iterator iterator = lista.iterator(); iterator.hasNext();) {
			LinkedHashMap object = (LinkedHashMap) iterator.next();
			String idDocumento = String.valueOf(object.get("id"));
			if (StringUtils.isNotBlank(idDocumento)) {
				ClpbDocumentoMovArticulo documento = obtenerDocumentoAsignacionArticulo(Long
						.parseLong(idDocumento));
				listaDocumentos.add(documento);
			}
		}
		return listaDocumentos;

	}


	public void guardarAsignacionArticulo(ClpbDocumentoMovArticulo documentoMovArticulo){
		
		//se inicia la transaccion para guardar todo el bloque
		try{
			
			Long coAlmacenOrigen  = documentoMovArticulo.getClpbAlmacenOrigen().getId();
			Long coAlmacenDestino = documentoMovArticulo.getClpbAlmacenDestino().getId();
			Long coCatalogo = documentoMovArticulo.getClpmCatalogo().getId();
		
			List<BNAsignacionArticuloCatalogoDetalle> listDetalle = documentoMovArticulo.getDetalle();
			ClpmCatalogo catalogo = obtenerCatalogo(coCatalogo);		
			
			//Armando el objeto del maestro
			documentoMovArticulo.setDaFechaDocumento(Calendar.getInstance());
			documentoMovArticulo.setCoUsuarioCreador(getUsuarioLogueado().getUsername());
			documentoMovArticulo.setDaFechaCreacion(Calendar.getInstance());
			documentoMovArticulo.setStDocumentoMovArticulo(Boolean.TRUE);
			documentoMovArticulo.setStIndicadorTipoDocumento(CLPConstantes.ST_DOCUMENTO_ASIGNACION_ARTICULO_A_CATALOGO);
			
			//lo guardamos para darle su referencia a sus detalles
			getHibernateTemplate().saveOrUpdate(documentoMovArticulo);
			
			StringBuffer query = new StringBuffer();
			List<ClpdDocumentoMovArticulo> listaDetalles = new ArrayList<ClpdDocumentoMovArticulo>();		
			List<ClpmTransaccionArticulo> listaTransacciones = new ArrayList<ClpmTransaccionArticulo>();
			List<ClpmStockAlmacenCatalogo> listaStockAlmCat = new ArrayList<ClpmStockAlmacenCatalogo>();		
			
			int indice = 0;
			String[] arrayStr = new String[listDetalle.size()*4];
			
			for (Iterator<BNAsignacionArticuloCatalogoDetalle> iter = listDetalle.iterator(); iter.hasNext(); ) {
				
				BNAsignacionArticuloCatalogoDetalle detDocumento = iter.next();			
				if (detDocumento.getCodigoArticulo() != null){
					
					BigDecimal vaStockDisAsig = detDocumento.getStockDisponibleAsignado();
					ClpdArticulo articulo = obtenerArticulo(detDocumento.getCodigoArticulo());			
					ClprPremioCatalogo premio = obtenerPremio(detDocumento.getCodigoPremio());				
					
					//Detalle movimientos del documento
					ClpdDocumentoMovArticulo documentoMov = new ClpdDocumentoMovArticulo();			
					documentoMov.setClpbDocumento(documentoMovArticulo);
					documentoMov.setClpdArticulo(articulo);	
					documentoMov.setVaStockDisponibleAsignado(vaStockDisAsig);			
					documentoMov.setClprPremio(premio);
					documentoMov.setStDocumentoMovArticulo(Boolean.TRUE);
					documentoMov.setCoAlmacenDestino(coAlmacenDestino);
					documentoMov.setCoCatalogoDestino(coCatalogo);			
					documentoMov.setCoUsuarioCreador(getUsuarioLogueado().getUsername());
					documentoMov.setDaFechaCreacion(Calendar.getInstance());				
					
					//Detalle actualizacion de articulos
					query = new StringBuffer();
					query.append(" update clpd_articulo ");
					query.append(" set ");
					query.append(" 		va_stock_disponible = decode(va_stock_disponible,null,"+vaStockDisAsig.negate()+",va_stock_disponible - "+vaStockDisAsig+"),");
					query.append(" 		co_usuario_modificador = '").append(getUsuarioLogueado().getUsername()).append("',");
					query.append(" 		da_fecha_modificacion = sysdate");
					query.append(" where trim(co_codigo_articulo) = '").append(detDocumento.getCodigoArticulo().trim()).append("'");
					
					arrayStr[indice] = query.toString();
					indice++;
					
					//Actualiza el Premio Catalogo		 
					query = new StringBuffer();
					query.append(" update clpr_premio_catalogo ");
					query.append(" set ");
					query.append(" 		va_stock_catalogo  = decode(va_stock_catalogo,null,"+vaStockDisAsig+",va_stock_catalogo + "+vaStockDisAsig+"),");
					query.append(" 		va_stock_catalogo_espejo = decode(va_stock_catalogo_espejo,null,"+vaStockDisAsig+",va_stock_catalogo_espejo + "+vaStockDisAsig+"),");
					query.append(" 		co_usuario_modificador = '").append(getUsuarioLogueado().getUsername()).append("',");
					query.append(" 		da_fecha_modificacion = sysdate");
					query.append(" where trim(co_codigo_premio) = '").append(detDocumento.getCodigoPremio().trim()).append("'");
					query.append(" and co_catalogo = ").append(catalogo.getId());
					
					arrayStr[indice] = query.toString();
					indice++;
					
					//TRANSACCION DE ENTRADA
					ClpmTransaccionArticulo transaccion = new ClpmTransaccionArticulo();
					transaccion.setClpdArticulo(articulo);
					transaccion.setCoCodigoArticulo(detDocumento.getCodigoArticulo());
					transaccion.setStIndicadorTipoMovimiento(CLPConstantes.ASIGNACION_STOCK_A_CATALOGO_DE_ARTICULO_QUE_MANEJA_STOCK);
					transaccion.setVaCantidad(vaStockDisAsig);
					transaccion.setClpbAlmacen(documentoMovArticulo.getClpbAlmacenDestino());//CONSULTAR SUSAN
					transaccion.setClpmCatalogo(catalogo);
					transaccion.setClprPremio(premio);
					transaccion.setCoCodigoPremio(premio.getCoCodigoPremio());
					transaccion.setClpbDocumentoMovArticulo(documentoMovArticulo);			
					transaccion.setCoUsuarioCreador(getUsuarioLogueado().getUsername());
					transaccion.setDaFechaCreacion(Calendar.getInstance());
	
					//TRANSACCION DE SALIDA
					
					ClpmTransaccionArticulo transaccionSalida = new ClpmTransaccionArticulo();
					transaccionSalida.setClpdArticulo(articulo);
					transaccionSalida.setCoCodigoArticulo(detDocumento.getCodigoArticulo());
					transaccionSalida.setStIndicadorTipoMovimiento(CLPConstantes.ASIGNACION_STOCK_A_CATALOGO_DE_ARTICULO_QUE_MANEJA_STOCK);
					transaccionSalida.setVaCantidad(vaStockDisAsig.negate());
					transaccionSalida.setClpbAlmacen(documentoMovArticulo.getClpbAlmacenOrigen());
					transaccionSalida.setClprPremio(premio);
					transaccionSalida.setCoCodigoPremio(premio.getCoCodigoPremio());
					transaccionSalida.setClpbDocumentoMovArticulo(documentoMovArticulo);			
					transaccionSalida.setCoUsuarioCreador(getUsuarioLogueado().getUsername());
					transaccionSalida.setDaFechaCreacion(Calendar.getInstance());
					
	
					//Se actualiza el stock disponible catalogo para ese almacen sin "catalogo"
										
					query = new StringBuffer();
					query.append(" update clpm_stock_almacen_catalogo ");
					query.append(" set ");
					query.append(" 		va_cantidad = decode(va_cantidad,null,"+(vaStockDisAsig.negate())+",va_cantidad - "+vaStockDisAsig+"),");
					query.append(" 		co_usuario_modificador = '").append(getUsuarioLogueado().getUsername()).append("' ,");
					query.append("		da_fecha_modificacion  = sysdate ");
					query.append(" where 1 = 1  ");
					query.append(" and co_articulo = ").append(documentoMov.getClpdArticulo().getId());
					query.append(" and co_almacen = ").append(coAlmacenOrigen);
					query.append(" and co_catalogo is null ");

					arrayStr[indice] = query.toString();
					indice++;
					
					//Verificar la existencia del registro con el catalogo.
					ClpmStockAlmacenCatalogo stocAlCat = obtenerStockAlmCata(articulo.getId(),
					coAlmacenDestino , coCatalogo);
					
					if (null == stocAlCat){
						
						//No Existe el registro con el articulo, almacen y catalogo (INSERT)
						ClpmStockAlmacenCatalogo sAlmCatcBean = new ClpmStockAlmacenCatalogo();
						sAlmCatcBean.setClpdArticulo(articulo);
						sAlmCatcBean.setClpbAlmacen(documentoMovArticulo.getClpbAlmacenDestino());
						sAlmCatcBean.setClpmCatalogo(catalogo);
						sAlmCatcBean.setVaCantidad(vaStockDisAsig);
						sAlmCatcBean.setVaStockCatalogo(vaStockDisAsig);
						sAlmCatcBean.setVaStockCatalogoEspejo(vaStockDisAsig);
						sAlmCatcBean.setStStockAlmacenCatalogo(Boolean.TRUE);					
						sAlmCatcBean.setClprPremioCatalogo(premio);
						sAlmCatcBean.setCoUsuarioCreador(getUsuarioLogueado().getUsername());
						sAlmCatcBean.setDaFechaCreacion(Calendar.getInstance());
						
						//lista Stock Catalogo Almacen
						listaStockAlmCat.add(sAlmCatcBean);
						
						// query para no dejar vacio el indice
						arrayStr[indice] = ValidationUtil.getQueryDefault();
						indice++;
				
					} else {
						
						//Si Existe el registro con el articulo, almacen y catalogo (UPDAT)
						StringBuffer querySac = new StringBuffer();
						querySac.append(" update clpm_stock_almacen_catalogo ");
						querySac.append(" set ");
						querySac.append(" 		va_cantidad = decode(va_cantidad,null,"+vaStockDisAsig+",va_cantidad + "+vaStockDisAsig+"),");
						querySac.append(" 		va_stock_catalogo = decode(va_stock_catalogo,null,"+vaStockDisAsig+",va_stock_catalogo + "+vaStockDisAsig+"),");
						querySac.append(" 		va_stock_catalogo_espejo = decode(va_stock_catalogo_espejo,null,"+vaStockDisAsig+",va_stock_catalogo_espejo + "+vaStockDisAsig+"),");
						querySac.append(" 		co_usuario_modificador = '").append(getUsuarioLogueado().getUsername()).append("' ,");
						querySac.append(" 		da_fecha_modificacion = sysdate");
						querySac.append(" where  ");
						querySac.append("  co_articulo = ").append(articulo.getId()).append(" ");
						querySac.append("  and co_almacen  = ").append(coAlmacenDestino).append(" ");
						querySac.append("  and co_catalogo = ").append(catalogo.getId());					
						
						arrayStr[indice] = querySac.toString();
						indice++;
					}			
					
				
					//lista de detalle de movimientos
					listaDetalles.add(documentoMov);		
					
					//lista de transacciones
					listaTransacciones.add(transaccion);		
					listaTransacciones.add(transaccionSalida);				
				
				}else{					
					// query 1 para no dejar vacio el indice de lo contrario ocurrira una excepcion
					arrayStr[indice] = ValidationUtil.getQueryDefault();
					indice++;
					
					// query 2 para no dejar vacio el indice de lo contrario ocurrira una excepcion
					arrayStr[indice] = ValidationUtil.getQueryDefault();
					indice++;
					
					// query 3 para no dejar vacio el indice de lo contrario ocurrira una excepcion
					arrayStr[indice] = ValidationUtil.getQueryDefault();
					indice++;
					
					// query 4 para no dejar vacio el indice de lo contrario ocurrira una excepcion
					arrayStr[indice] = ValidationUtil.getQueryDefault();
					indice++;
				}		
			}
			
			getHibernateTemplate().saveOrUpdateAll(listaDetalles);
			getHibernateTemplate().saveOrUpdateAll(listaTransacciones);
			getHibernateTemplate().saveOrUpdateAll(listaStockAlmCat);
			
			getHibernateTemplate().flush();
			jdbcTemplate.batchUpdate(arrayStr);
			
			for (int i = 0; i < arrayStr.length; i++) {
				System.out.println(i+"* update detalle guardarAsignacionArticulo(): "+arrayStr[i]);
			}
		
		}catch(Exception e){
			
			getHibernateTemplate().clear();
			log.info(e.getMessage());
		}		
	}
	
	@SuppressWarnings("unchecked")
	public ClpbAlmacen obtenerAlmacen(Long idAlmacen) {
		Criteria criteria = DetachedCriteria.forClass(ClpbAlmacen.class).getExecutableCriteria(getSessionFactory().getCurrentSession());
		criteria.add(Restrictions.eq("id", idAlmacen));
		List<ClpbAlmacen> sacat = criteria.list();
		if(!sacat.isEmpty()){
			return sacat.get(0);
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public ClpdArticulo obtenerArticulo(
			BNAsignacionArticuloCatalogoDetalle detalle) {
		Criteria criteria = DetachedCriteria.forClass(ClpdArticulo.class).getExecutableCriteria(getSessionFactory().getCurrentSession());
		criteria.add(Restrictions.eq("coCodigoArticulo", detalle.getCodigoArticulo().trim()).ignoreCase());		
		List<ClpdArticulo> articulos = criteria.list();
		if(!articulos.isEmpty()){
			return articulos.get(0);
		}
		return null;

	}

	@SuppressWarnings("unchecked")
	public ClpdArticulo obtenerArticulo(String coCodigoArticulo) {
		// TODO Auto-generated method stub
		Criteria criteria = DetachedCriteria.forClass(ClpdArticulo.class).getExecutableCriteria(getSessionFactory().getCurrentSession());
		criteria.add(Restrictions.eq("coCodigoArticulo", coCodigoArticulo.trim()).ignoreCase());		
	
		List<ClpdArticulo> articulos = criteria.list();
		if(!articulos.isEmpty()){
			return articulos.get(0);
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public ClpmCatalogo obtenerCatalogo(Long idCatalogo) {
		Criteria criteria = DetachedCriteria.forClass(ClpmCatalogo.class).getExecutableCriteria(getSessionFactory().getCurrentSession());
		criteria.add(Restrictions.eq("id", idCatalogo));		
	
		List<ClpmCatalogo> catalogos = criteria.list();
		if(!catalogos.isEmpty()){
			return catalogos.get(0);
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public ClpbDocumentoMovArticulo obtenerDocumentoAsignacionArticulo(Long id) {
		StringBuffer query = new StringBuffer();
		query = query.append(" SELECT clpb_doc.id  as id, ");
				query.append("        clpb_doc.de_documento  as deDocumento, ");
				query.append("        clpb_doc.de_observaciones as deObservaciones, ");
				query.append("        clpb_doc.co_catalogo as coCatalogo, ");
				query.append("        catalogo.de_catalogo as deCatalogo, ");
				query.append("        clpb_doc.co_almacen_origen as coAlmacenOrigen, ");
				query.append("        clpb_doc.co_almacen_destino as coAlmacenDestino, ");
				query.append("        almacen_or.de_almacen as deAlmacenOrigen, ");
				query.append("        almacenDe.de_almacen as deAlmacenDestino ");        
				query.append("        ");
				query.append(" FROM clpb_documento_mov_articulo clpb_doc ");  
				query.append("      join clpm_catalogo catalogo on ");
				query.append("        catalogo.id = clpb_doc.co_catalogo ");        
				query.append("      join clpb_almacen almacen_or on "); 
				query.append("        almacen_or.id = clpb_doc.co_almacen_origen ");                
				query.append("      join clpb_almacen almacenDe on ");
				query.append("        almacenDe.id = clpb_doc.co_almacen_destino	"); 
				query.append(" WHERE 1 = 1 "); 
				query.append("      and clpb_doc.id = " +id+ " ");
				query.append("      and clpb_doc.st_documento_mov_articulo = '" + CLPConstantes.ST_VERDADERO+ "' ");
				
				
				List<ClpbDocumentoMovArticulo> documentos= findListOfBeans(query.toString(), null, ClpbDocumentoMovArticulo.class);				
				if(!documentos.isEmpty()){
					return documentos.get(0);
				}
				return new ClpbDocumentoMovArticulo();
	}

	@SuppressWarnings("unchecked")
	public List<ClpbDocumentoMovArticulo> obtenerDocumentoAsignacionArticulos() {
		Criteria criteria = DetachedCriteria.forClass(
				ClpbDocumentoMovArticulo.class).getExecutableCriteria(
				getSessionFactory().getCurrentSession());
		criteria.setMaxResults(CLPConstantes.MAXIMO_RESULTADO_INICIAL);
		criteria.add(Restrictions.eq("stIndicadorTipoDocumento", CLPConstantes.ST_DOCUMENTO_ASIGNACION_ARTICULO_A_CATALOGO));
		criteria.add(Restrictions.eq("stDocumentoMovArticulo", Boolean.TRUE));
		criteria.addOrder(Order.desc("id"));
		List<ClpbDocumentoMovArticulo> lista = criteria.list();
		return lista;
	}

	@SuppressWarnings("unchecked")
	public ClprPremioCatalogo obtenerPremio(String coCodigoPremio) {
		Criteria criteria = DetachedCriteria.forClass(ClprPremioCatalogo.class).getExecutableCriteria(getSessionFactory().getCurrentSession());
		criteria.add(Restrictions.eq("coCodigoPremio", coCodigoPremio.trim()).ignoreCase());		
	
	List<ClprPremioCatalogo> premios = criteria.list();
	if(!premios.isEmpty()){
		return premios.get(0);
	}
	return null;
	}

	@SuppressWarnings("unchecked")
	public ClprPremioCatalogo obtenerPremio(String coCodigoPremio,Long idCatalogo) {
		Criteria criteria = DetachedCriteria.forClass(ClprPremioCatalogo.class).getExecutableCriteria(getSessionFactory().getCurrentSession());
		criteria.add(Restrictions.eq("coCodigoPremio", coCodigoPremio.trim()).ignoreCase());		
		criteria.add(Restrictions.eq("clpmCatalogo.id", idCatalogo));
	List<ClprPremioCatalogo> premios = criteria.list();
	if(!premios.isEmpty()){
		return premios.get(0);
	}
	return null;
	}
	
	@SuppressWarnings("unchecked")
	public ClpmStockAlmacenCatalogo obtenerStockAlmCata(Long idArticulo,
			Long idAlmacen, Long idCatalogo) {
		Criteria criteria = DetachedCriteria.forClass(ClpmStockAlmacenCatalogo.class).getExecutableCriteria(getSessionFactory().getCurrentSession());
		criteria.add(Restrictions.eq("clpdArticulo.id", idArticulo));
		criteria.add(Restrictions.eq("clpbAlmacen.id",idAlmacen));
		criteria.add(Restrictions.eq("clpmCatalogo.id", idCatalogo));
		
		List<ClpmStockAlmacenCatalogo> sacat = criteria.list();
		if(!sacat.isEmpty()){
			return sacat.get(0);
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public ClpmStockAlmacenCatalogo obtenerStockAlmCata(Long idArticulo,
			Long idAlmacen) {
		Criteria criteria = DetachedCriteria.forClass(ClpmStockAlmacenCatalogo.class).getExecutableCriteria(getSessionFactory().getCurrentSession());
		criteria.add(Restrictions.eq("clpdArticulo.id", idArticulo));
		criteria.add(Restrictions.eq("clpbAlmacen.id",idAlmacen));
		//criteria.add(Restrictions.eq("clpmCatalogo.id", null));
		
		List<ClpmStockAlmacenCatalogo> sacat = criteria.list();
		if(!sacat.isEmpty()){
			return sacat.get(0);
		}
		return null;
	}
}
